
;*******************************************************
;
;	SCSI Driver Set Volume/Disk Parms code.
;
;	Written by Matt Gulick.		Started April 17,1991
;
;	Copyright Apple Computer, Inc. 1990
;
;*******************************************************

;*******************************************************
;
;	This file contains the Set Volume/Disk Parms as
;	defined in the ERS.
;
;*******************************************************

;*******************************************************
;
;	Revision History:
;
;*******************************************************

;	April 17,	1991	File started.

				IMPORT		chk_count
				IMPORT		length
				IMPORT		rqst
				IMPORT		gc_buff_ptr
				IMPORT		count
				IMPORT		temp
				IMPORT		error
				IMPORT		ddm_index
				IMPORT		pre_load_ddm
				IMPORT		pdata_block
				IMPORT		find_drvr_part
				IMPORT		set_drvr_ndex

				EJECT
			
;*******************************************************
;
;	's_vol_parms'
;
;	This routine is used to set information about the
;	volume.  Calls should have the DIB Pointer set to
;	the volume for which the information is being
;	requested.
;
;	The structure of the parameter list is defined in the
;	SCSI Driver ERS.  The parameters are going to depend
;	greatly on the type of device that this driver is
;	written for.  That means that the info for the Scanner
;	will not be the same in any form as that for a Hard
;	Disk, or a Tape drive.  These calls will be particular
;	for the device type supported.
;
;	Called via 'JSR'
;
;	Inputs:		[dib_ptr]	=	Target DIB			(LONG)
;				[buff_ptr]	=	Data Buffer Pointer	(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Returns via 'RTS'
;
;	Outputs:	Acc			=	0
;				Carry		=	0
;	or
;				Acc			=	Error
;				Carry		=	1
;
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		See Spec.
;
;*******************************************************

				EXPORT		svp
svp
											;
											; Check the Request Count.  Volume calls
											; need 2 bytes.
											;
				lda		<rqst_cnt+2
				bne		@rqst_cnt_ok
				lda		<rqst_cnt
				cmp		#$0002
				blt		@bad_cnt
											;
											; Check Bitmap.
											;
@rqst_cnt_ok	lda		[buff_ptr]
											;
											; Do the Volume Parms Here.
											; Acc = Bitmap on entry.
											;
				sta		|bitmap
				and		#vconf_resv2++\
						vconf_resv3++\		;Check Bits that are not supported
						vconf_resv4++\		;at this time.
						vconf_resv5++\
						vconf_resv6
				bne		@exit_parm			;If unsupported bit set then error out.
											;
											; Check for Remount Bit
											;
				lda		|bitmap
				and		#vconf_remount
				beq		@next_0
				jsr		remount_vol
											;
											; Check Status Bits Flag.  If set, then we
											; use the low byte of this word to set the
											; status bits in the Partition Map and in
											; the DIB Status.
											;
@next_0			lda		|bitmap
				and		#vconf_set_stat
				beq		@next_1
				jsr		set_stat_bits

@next_1			bcs		@rts
				lda		#$0002
				sta		<trans_cnt
				lda		#null
				sta		<trans_cnt+2
				clc
@rts			rts
											;
											; Error exit point.
											;
@bad_cnt		lda		#drvr_bad_cnt
				brl		exit_none
											;
											; Drive is Offline.
											;
@not_online		lda		#drvr_off_line
				sec
				rts
											;
											; Not from a partition.
											;
@exit_parm		brl		exit_parm
											;
											; Routines used by the above code to
											; perform the requested task.
											;
remount_vol
											;
											; Mark this DIB as Switched and Hard
											; Offline.
											;
				ldy		#dib.dvcflag
				lda		[dib_ptr],y
				ora		#dvc_online++\
						dvc_switch
				and		#dvc_hardofl--\
						$ffff
				sta		[dib_ptr],y
											;
											; Generate a Disk Switched Event
											;
				jsr		set_disk_sw
											;
											; Clean Exit.
											;
				rts

set_stat_bits
											;
											; Set the Status Bits in the Partition
											; Map entry to mach those supplied by
											; this call.
											;
											; Check to see if this Volume is Online.
											;
				ldy		#dib.dvcflag
				lda		[dib_ptr],y
				and		#dvc_online
				beq		@not_online
											;
											; Validate that this DIB is from
											; a Partition Map Entry.
											;
				ldy		#dib.start_blk
				lda		[dib_ptr],y
				ldy		#dib.start_blk+2
				ora		[dib_ptr],y
				bne		@over
											;
											; Not from a partition.
											;
				lda		#drvr_bad_parm
				sec
				rts
											;
											; Get block that contains this
											; DIB's Partition Map Entry.
											;
@over			ldy		#dib.part_blk
				lda		[dib_ptr],y
				sta		|rpm_blk_num
				sta		|wpm_blk_num
											;
											; Tell the code that we have already
											; set the Block Number and that this
											; is not a startup call.
											;
				dec		|stat_cont			;This is from a Status or Control Call
				dec		|rebuild			;And not from a startup Call
											;
											; Issue the Read PM Block Call.
											;
				jsr		|read_pm_blk
				bcs		@bad_exit			;There was an error.
											;
											; Is what we read a Partition Map?
											;
				lda		|pm.Sig\
						+internal_buff
				cmp		#Part_sig
				bne		@bad_exit			;Bad Data Read.
											;
											; Set the Status Byte
											;
				lda		|bitmap
				and		#$00ff
				sta		@temp
				lda		|pm.PartStatus+2\
						+internal_buff
				xba
				and		#$ff00
				ora		@temp
				xba
				sta		|pm.PartStatus+2\
						+internal_buff
											;
											; Issue the Write PM Block Call.
											;
				jsr		|write_pm_blk
				bcs		@bad_exit			;There was no error.
											;
											; Clean Exit
											;
@all_done		jsr		set_our_dp

				lda		@temp				;Update the DIB.
				and		#vconf_wr_enable++\
						vconf_rd_enable
				asl		a
				sta		@temp
				ldy		#dib.dvcchar
				lda		[dib_ptr],y
				and		#write_allow++\
						read_allow--\
						$ffff
				ora		@temp
				sta		[dib_ptr],y
											;
											; Generate a Disk Switched Event
											;
				jsr		set_disk_sw

				lda		#no_error
				clc
				rts
											;
											; Data Area.
											;
@temp			dc.w	null
											;
											; Not from a partition.
											;
@not_online		lda		#drvr_off_line
				bra		exit_none
											;
											; Error exit point.
											;
@bad_exit		jsr		set_our_dp
				lda		#drvr_io
				bra		exit_none
											;
											; Error exit point.
											;
@bad_cnt		lda		#drvr_bad_cnt
				bra		exit_none
											;
											; Use this code to exit when no data is
											; being returned.
											;
exit_parm		lda		#drvr_bad_parm
exit_none		stz		<trans_cnt
				stz		<trans_cnt+2
				cmp		#$0001
				rts

				EJECT
							
;*******************************************************
;
;	's_disk_parms'
;
;	This routine is used to set information about the
;	disk in question.  The DIB Pointer must point to
;	the head DIB if this is a linked device.
;
;	The structure of the parameter list is defined in the
;	SCSI Driver ERS.  The parameters are going to depend
;	greatly on the type of device that this driver is
;	written for.  That means that the info for the Scanner
;	will not be the same in any form as that for a Hard
;	Disk, or a Tape drive.  These calls will be particular
;	for the device type supported.
;
;	Called via 'JSR'
;
;	Inputs:		[dib_ptr]	=	Target DIB			(LONG)
;				[buff_ptr]	=	Data Buffer Pointer	(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Returns via 'RTS'
;
;	Outputs:	Acc			=	0
;				Carry		=	0
;	or
;				Acc			=	Error
;				Carry		=	1
;
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		See Spec.
;
;*******************************************************

				EXPORT		sdp
sdp
											;
											; Check the Request Count.  Volume calls
											; need at least 4 bytes.  Disk calls need
											; more and that will be verified there.
											;
				lda		<rqst_cnt+2
				bne		@rqst_cnt_ok
				lda		<rqst_cnt
				cmp		#$001A
				blt		@bad_cnt
											;
											; Check to see if this Volume is Online.
											;
@rqst_cnt_ok	ldy		#dib.dvcflag
				lda		[dib_ptr],y
				and		#dvc_online
				beq		@not_online
											;
											; Validate that this DIB is from
											; a Partition Map Entry.
											;
				ldy		#dib.start_blk
				lda		[dib_ptr],y
				ldy		#dib.start_blk+2
				ora		[dib_ptr],y
				bne		do_sdisk
											;
											; Not from a partition.
											;
				lda		#drvr_bad_parm
				brl		exit_none
											;
											; Not from a partition.
											;
@not_online		lda		#drvr_off_line
				brl		exit_none
											;
											; Error exit point.
											;
@bad_exit		jsr		set_our_dp
				lda		#drvr_io
				brl		exit_none
											;
											; Error exit point.
											;
@bad_cnt		lda		#drvr_bad_cnt
				brl		exit_none
											;
											; Set Disk Calls are handled here.
											;
do_sdisk		stz		|error
											;
											; Preserve the Users Buffer Pointer.
											;
				lda		<buff_ptr
				sta		gc_buff_ptr
				lda		<buff_ptr+2
				sta		gc_buff_ptr+2
											;
											; If a call is unacceptable an error will
											; be returned and the transfer length
											; will reflect the buffer size that is
											; needed if the current one is too small.
											;
											; Check Set DDM Info
											;
				ldy		#disk_pl.ddm_buff_len
				lda		[buff_ptr],y
				bne		@chk_ddm_len
				ldy		#disk_pl.ddm_buff_ptr
				ora		[buff_ptr],y
				ldy		#disk_pl.ddm_buff_ptr+2
				ora		[buff_ptr],y
				bne		@bad_ddm_len
				bra		@pre_load_ddm
											;
											; Is the DDM Buffer Long enough?
											;
@chk_ddm_len	cmp		#$0200
				beq		@do_ddm
											;
											; Bad request length for the DDM
											;
@bad_ddm_len	lda		#$0200						
				ldy		#disk_pl.ddm_trns_len
				sta		[buff_ptr],y
				lda		#drvr_bad_cnt
				sta		|error
				bra		@pre_load_ddm
											;
											; Set DDM.
											;
@do_ddm			jsr		set_ddm
				bcc		@chk_vol
				brl		@disk_done
											;
											; If called, the user is not
											; setting the DDM and we need
											; to load it into our own buffer.
											;
@pre_load_ddm	jsr		pre_load_ddm
				bcc		@chk_vol
				brl		@disk_done
											;
											; Check Set Volume Info
											;
@chk_vol		ldy		#disk_pl.vol_buff_len
				lda		[buff_ptr],y
				bne		@chk_vol_len
				ldy		#disk_pl.vol_buff_ptr
				ora		[buff_ptr],y
				ldy		#disk_pl.vol_buff_ptr+2
				ora		[buff_ptr],y
				bne		@bad_vol_len
				bra		@chk_drvr
											;
											; Is the DDM Buffer Long enough?
											;
@chk_vol_len	cmp		#$0200
				beq		@do_vol
											;
											; Bad request length for the DDM
											;
@bad_vol_len	lda		#$0200						
				ldy		#disk_pl.vol_trns_len
				sta		[buff_ptr],y
				lda		#drvr_bad_cnt
				sta		|error
				bra		@chk_drvr
											;
											; Set Volume Info.
											;
@do_vol			jsr		set_vol
				bcs		@disk_done
											;
											; Check Set Driver Info
											;
@chk_drvr		clc
				lda		|ddm_index
				adc		#$0004
				tay
				lda		[ddm_buff],y
				xba
				asl		a					;Convert Blocks to Bytes
				stz		|drvr_size
				stz		|drvr_size+2
				sta		|drvr_size+1
											;
											; Check Set Driver Data
											;
				ldy		#disk_pl.drvr_buff_len
				lda		[buff_ptr],y
				bne		@chk_drvr_len
				ldy		#disk_pl.drvr_buff_ptr
				ora		[buff_ptr],y
				ldy		#disk_pl.drvr_buff_ptr+2
				ora		[buff_ptr],y
				bne		@bad_drvr_len
				bra		@disk_done1
											;
											; Is the DDM Buffer Long enough?
											;
@chk_drvr_len	cmp		|drvr_size
				blt		@do_drvr
				beq		@do_drvr
											;
											; Bad request length for the DDM
											;
@bad_drvr_len	lda		|drvr_size					
				ldy		#disk_pl.drvr_trns_len
				sta		[buff_ptr],y
				lda		#drvr_bad_cnt
				bra		@disk_done
											;
											; Get Volume Info.
											;
@do_drvr		jsr		set_drvr
											;
											; All done.  Return the transfer
											; length and any error codes that
											; were encountered
											;
@disk_done		sta		|error
@disk_done1		lda		#$001A
				sta		<trans_cnt
				stz		<trans_cnt+2
											;
											; Replace the Buffer Pointer.
											;
				lda		gc_buff_ptr
				sta		<buff_ptr

				lda		gc_buff_ptr+2
				sta		<buff_ptr+2

				lda		|error
				cmp		#$0001
				rts
											;
											; Subroutines for this code.
											;
											; The first Routine is used to Write
											; the DDM from the callers buffer.
											;
set_ddm			jsr		set_drvr_ndex
											;
											; Tell the Main Driver where
											; our command structure resides.
											;
				lda		#@write_ddm
				sta		<scsi_mdrvr
				lda		#^@write_ddm
				sta		<scsi_mdrvr+2
											;
											; Set the user's buffer
											;
				ldy		#disk_pl.ddm_buff_ptr
				lda		[buff_ptr],y
				tax

				ldy		#disk_pl.ddm_buff_ptr+2

				lda		[buff_ptr],y
				sta		<buff_ptr+2
				sta		<ddm_buff+2			;Incase we need it for the Driver Code
				stx		<buff_ptr
				stx		<ddm_buff			;Incase we need it for the Driver Code
											;
											; Is what we are writing a Driver
											; Descriptor Map?
											;
				lda		[ddm_buff]
				cmp		#DDM_sig
				bne		@bad_exit1			;Bad Data.

				lda		#block_size
				sta		<rqst_cnt
				lda		#^block_size
				sta		<rqst_cnt+2
											;
											; Set internal command flag
											;
				dec		|internal
											;
											; Set the Partition call flag
											;
				dec		|f_partition
											;
											; Set the Call Type and Issue the
											; READ BLOCK Command.
											;
				lda		#scsit_cont
				sta		|call_type
											;
											; Issue the call.
											;
				jsr		check_532_rw
				php
											;
											; Replace the Buffer Pointer.
											;
				lda		gc_buff_ptr
				sta		<buff_ptr

				lda		gc_buff_ptr+2
				sta		<buff_ptr+2
											;
											; Check for Call Errors
											;
				plp
				bcs		@bad_exit1
											;
											; Add in the Length
											;
				lda		#block_size
				ldy		#disk_pl.ddm_trns_len
				sta		[buff_ptr],y
											;
											; Clean Exit.
											;
				lda		#$0000
				clc
				rts
											;
											; Error exit point.
											;
@bad_exit1		jsr		set_our_dp
				lda		#drvr_io
				sec
				rts
											;
											; Data for the WRITE BLOCK Command
											;
@write_ddm		dc.b		$0A
				dc.b		null
				dc.w		null
				dcb.b		10,null
											;
											; This Routine is used to set the
											; Volume Info from the callers buffer.
											;
set_vol
											;
											; Find the Partition Map Entry that matches
											; the data blocks used in the DDM.
											;
				ldy		ddm_index
				lda		[ddm_buff],y
				sta		|pdata_block

				iny
				iny
				lda		[ddm_buff],y
				sta		|pdata_block+2

				lda		#$0001				;Start looking here.
				ldx		#internal_buff
				ldy		#^internal_buff
				jsr		find_drvr_part
				bcs		@rts
											;
											; Set the Partition Map Block Number
											; that we need to Write.
											;
				sta		@write_vol_num
											;
											; Tell the Main Driver where
											; our command structure resides.
											;
				lda		#@write_vol
				sta		<scsi_mdrvr
				lda		#^@write_vol
				sta		<scsi_mdrvr+2
											;
											; Set the user's buffer
											;
				ldy		#disk_pl.vol_buff_ptr
				lda		[buff_ptr],y
				tax

				ldy		#disk_pl.vol_buff_ptr+2

				lda		[buff_ptr],y
				sta		<buff_ptr+2
				sta		<config_buff+2
				stx		<buff_ptr
				stx		<config_buff
											;
											; Is what we are writing a Driver
											; Descriptor Map?
											;
				lda		[config_buff]
				cmp		#Part_sig
				bne		@bad_exit1			;Bad Data Read.

				lda		#block_size
				sta		<rqst_cnt
				lda		#^block_size
				sta		<rqst_cnt+2
											;
											; Set internal command flag
											;
				dec		|internal
											;
											; Set the Partition call flag
											;
				dec		|f_partition
											;
											; Set the Call Type and Issue the
											; READ BLOCK Command.
											;
				lda		#scsit_cont
				sta		|call_type
											;
											; Issue the call.
											;
				jsr		check_532_rw
				php
											;
											; Replace the Buffer Pointer.
											;
				lda		gc_buff_ptr
				sta		<buff_ptr

				lda		gc_buff_ptr+2
				sta		<buff_ptr+2
											;
											; Check for Call Errors
											;
				plp
				bcs		@bad_exit1
											;
											; Add in the Length
											;
				lda		#block_size
				ldy		#disk_pl.vol_trns_len
				sta		[buff_ptr],y
											;
											; Clean Exit.
											;
				lda		#$0000
				clc
@rts			rts
											;
											; Error exit point.
											;
@bad_exit1		jsr		set_our_dp
				lda		#drvr_io
				sec
				rts
											;
											; Data for the WRITE BLOCK Command
											;
@write_vol		dc.b	$0A
				dc.b	null
@write_vol_num	dc.w	null
				dcb.b	10,null
											;
											; This Routine is used to set the
											; Driver Data into the callers buffer.
											;
set_drvr
											;
											; At this point the DDM is in Memory
											; and the Zero Page Pointer 'DDM_BUFF'
											; points to it.
											;
				ldy		ddm_index
				lda		[ddm_buff],y
				and		#%0001111100000000	;Allow Byte 1, bits 0-4 to pass
				ora		#$000A				;OR in the command number
				sta		@write_drvr

				iny
				iny
				lda		[ddm_buff],y
				sta		@block_num

				iny
				iny
				lda		[ddm_buff],y
				xba
				asl		a					;Cheap Multiply by $200
				stz		<rqst_cnt
				stz		<rqst_cnt+2		
				sta		<rqst_cnt+1
											;
											; Set the user's buffer
											;
				ldy		#disk_pl.drvr_buff_ptr
				lda		[buff_ptr],y
				tax

				ldy		#disk_pl.drvr_buff_ptr+2

				lda		[buff_ptr],y
				sta		<buff_ptr+2
				sta		<config_buff+2
				stx		<buff_ptr
				stx		<config_buff
											;
											; Tell the Main Driver where
											; our command structure resides.
											;
				lda		#@write_drvr
				sta		<scsi_mdrvr
				lda		#^@write_drvr
				sta		<scsi_mdrvr+2
											;
											; Set internal command flag
											;
				dec		|internal
											;
											; Set the Partition call flag
											;
				dec		|f_partition
											;
											; Set the Call Type and Issue the
											; WRITE BLOCK Command.
											;
				lda		#scsit_cont
				sta		|call_type
											;
											; Issue the call.
											;
				jsr		check_532_rw
				php
											;
											; Replace the Buffer Pointer.
											;
				lda		gc_buff_ptr
				sta		<buff_ptr

				lda		gc_buff_ptr+2
				sta		<buff_ptr+2
											;
											; Check for Call Errors
											;
				plp
				bcs		@bad_exit1
											;
											; Add in the Length
											;
				lda		<rqst_cnt
				ldy		#disk_pl.drvr_trns_len
				sta		[buff_ptr],y
											;
											; Clean Exit.
											;
				lda		#$0000
				rts
											;
											; Error exit point.
											;
@bad_exit1		jsr		set_our_dp
				lda		#drvr_io
				sec
				rts
											;
											; Command to Write the Driver Data
											;
@write_drvr		dc.b		$0A
				dc.b		null
@block_num		dc.w		null
				dcb.b		10,null
											;
											; Other Data Storage areas.
											;
				EXPORT		drvr_size
drvr_size		dc.l		null			;Driver Size in Bytes
				EXPORT		gc_buff_ptr
gc_buff_ptr		dc.l		null			;Their buffer pointer
				EXPORT		error
error			dc.w		null
				EXPORT		ddm_index
ddm_index		dc.w		null			;Index Into the DDM for the rqsted DRVR
bitmap			dc.w		null			;Bitmap supplied by user.

				EJECT
